package br.com.projetoia.dama;

import java.util.ArrayList;
import java.util.List;

import br.com.projetoia.dama.enums.WalkerTypeEnum;
import br.com.projetoia.dama.exception.GameException;

public class Board implements Cloneable {

	private House[][] board;

	private final List<Walker> whiteWalkers;

	private final List<Walker> blackWalkers;

	public static int LINE_LENGTH = 8;
	public static int COLUMN_LENGHT = 8;

	private final int[] houseValues = { 4, 4, 4, 4, 3, 3, 3, 4, 4, 2, 2, 3, 3, 1, 2, 4, 4, 2, 1, 3,
			3, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 4 };

	public Board() {
		this.whiteWalkers = new ArrayList<Walker>();
		this.blackWalkers = new ArrayList<Walker>();
	}

	public Board(House[][] board) {
		this.board = new House[8][8];
		this.whiteWalkers = new ArrayList<Walker>();
		this.blackWalkers = new ArrayList<Walker>();

		for (int i = 0; i < LINE_LENGTH; i++) {
			for (int j = 0; j < COLUMN_LENGHT; j++) {
				House house = board[i][j];
				if (house != null) {
					House newHouse = new House(house);
					this.board[i][j] = newHouse;

					Walker walker = newHouse.getWalker();
					if (walker != null) {
						if (walker.getType().equals(WalkerTypeEnum.WHITE)) {
							this.whiteWalkers.add(walker);
						} else {
							this.blackWalkers.add(walker);
						}
					}
				}
			}
		}

		System.out.println("CLONE FINISHED!");
	}

	public List<Walker> getWhiteWalkers() {
		return this.whiteWalkers;
	}

	public List<Walker> getBlackWalkers() {
		return this.blackWalkers;
	}

	/**
	 * Cria o tabuleiro.
	 */
	public void create() {
		this.board = new House[8][8];
		int initIndex = 0;
		House house;
		int houseValuesIndex = 0;

		for (int i = 0; i < LINE_LENGTH; i++) {
			Walker walker;
			for (int x = initIndex; x < COLUMN_LENGHT; x += 2) {
				house = new House();
				Position position = new Position(i, x);
				house.setPosition(position);
				house.setValue(this.houseValues[houseValuesIndex]);
				this.board[i][x] = house;

				if (i <= 2) {
					walker = new Walker(5, WalkerTypeEnum.WHITE, position);
					house.setWalker(walker);
					this.whiteWalkers.add(walker);
				} else if (i >= 5) {
					walker = new Walker(5, WalkerTypeEnum.BLACK, position);
					house.setWalker(walker);
					this.blackWalkers.add(walker);
				}

				houseValuesIndex++;
			}

			initIndex = (initIndex == 0) ? 1 : 0;
		}

	}

	/**
	 * Exibe o tabuleiro.
	 */
	public void printBoard() {
		for (int i = 0; i < LINE_LENGTH; i++) {
			for (int j = 0; j < COLUMN_LENGHT; j++) {
				House house = this.board[i][j];
				if (house == null) {
					// System.out.print("_");
					System.out.printf("%5s", "[   ]");
				} else {
					if (house.getWalker() != null) {
						// System.out.print(house.getValue());
						System.out.print(house.getWalker().getType().toString());
					} else {
						// System.out.print(house.getValue());
						System.out.printf("%5s", "[   ]");
					}
				}

			}
			System.out.print("\n");

		}
		System.out.println("");
	}

	public House getHouse(int line, int column) throws GameException {
		if (line >= LINE_LENGTH || line < 0) {
			throw new GameException("Linha inválida!");
		}

		if (column >= COLUMN_LENGHT || column < 0) {
			throw new GameException("Coluna inválida! " + column);
		}

		return this.board[line][column];
	}

	/**
	 * Retorna as peças brancas que podem ser movidas.
	 * 
	 * @return
	 * @throws GameException
	 */
	public List<Walker> getWhiteWalkersCanBeMove() throws GameException {
		List<Walker> walkersCanBeMoved = this.getWalkerCanBeMove(WalkerTypeEnum.WHITE);
		return walkersCanBeMoved;
	}

	/**
	 * Retorna as peças pretas que podem ser movidas.
	 * 
	 * @return
	 * @throws GameException
	 */
	public List<Walker> getBlackWalkerCanBeMove() throws GameException {
		List<Walker> walkersCanBeMoved = this.getWalkerCanBeMove(WalkerTypeEnum.BLACK);
		return walkersCanBeMoved;
	}

	/**
	 * Retorna as peças que podem ser movidas.
	 * 
	 * @param walkerType
	 *            tipo da peça (BLACK ou WHITE).
	 * @return
	 * @throws GameException
	 */
	public List<Walker> getWalkerCanBeMove(WalkerTypeEnum walkerType) throws GameException {
		List<Walker> walkersCanBeMoved = new ArrayList<Walker>();
		for (int i = 0; i < LINE_LENGTH; i++) {
			for (int j = 0; j < COLUMN_LENGHT; j++) {

				House house = this.board[i][j];

				if (house == null) {
					continue;
				}

				if (house.getWalker() != null) {
					if (house.getWalker().getType().equals(walkerType)) {
						if (this.canBeMove(house, walkerType)) {
							walkersCanBeMoved.add(house.getWalker());
						}
					}
				}

			}
		}
		return walkersCanBeMoved;
	}

	/**
	 * Verifica se uma peça pode ser movida a partir dessa casa.
	 * 
	 * @param house
	 * @param walkerType
	 * @return
	 * @throws GameException
	 */
	private boolean canBeMove(House house, WalkerTypeEnum walkerType) throws GameException {
		boolean canBeMove = false;

		int lineIncrement = walkerType.equals(WalkerTypeEnum.WHITE) ? 1 : -1;

		Position position = house.getPosition();
		int newLine = position.getLine() + lineIncrement;
		if (newLine < LINE_LENGTH) {
			int columnIncrement = position.getColumn() + 1;

			canBeMove = this.isValidMoveTo(newLine, columnIncrement);

			if (canBeMove == false) {
				int columnDecrement = position.getColumn() - 1;
				canBeMove = this.isValidMoveTo(newLine, columnDecrement);
			}
		}
		return canBeMove;
	}

	/**
	 * Verifica se e valido mover uma peça para as coordenadas passadas como
	 * parametro.
	 * 
	 * @param newLine
	 * @param columnIncrement
	 * @return
	 * @throws GameException
	 */
	public boolean isValidMoveTo(int newLine, int columnIncrement) throws GameException {
		boolean isValidMove = false;
		if (columnIncrement >= 0 && columnIncrement < LINE_LENGTH) {
			if (!this.houseHasWalker(newLine, columnIncrement)) {
				isValidMove = true;
			}
		} else {
			isValidMove = false;
		}
		return isValidMove;
	}

	/**
	 * Verifica se a casa contém uma peça.
	 * 
	 * @param line
	 * @param column
	 * @return
	 * @throws GameException
	 */
	private boolean houseHasWalker(int line, int column) throws GameException {
		boolean hasWalker = false;

		House houseToMove = this.getHouse(line, column);
		if (houseToMove.getWalker() != null) {
			hasWalker = true;
		}

		return hasWalker;
	}

	public void setBoard(House[][] board) {
		this.board = board;
	}

	public House[][] getBoard() {
		return this.board;
	}

	@Override
	public Board clone() throws CloneNotSupportedException {
		return (Board) super.clone();
	}
}
